package cn.iocoder.yudao.module.ad.framework.core.channel.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.ad.api.advertiser.dto.AdvertiserRespDTO;
import cn.iocoder.yudao.module.ad.api.channel.dto.ClueSyncReqDTO;
import cn.iocoder.yudao.module.ad.api.channel.dto.ClueSyncRespDTO;
import cn.iocoder.yudao.module.ad.api.channel.dto.TokenGenRespDTO;
import cn.iocoder.yudao.module.ad.framework.core.channel.AdChannelClient;
import cn.iocoder.yudao.module.ad.framework.core.enums.clue.AdClueStatusEnum;
import cn.iocoder.yudao.module.ad.framework.core.enums.clue.AdClueTypeEnum;
import cn.iocoder.yudao.module.ad.framework.core.properties.AdChannelProperties;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.util.*;

/**
 * 抖音飞鱼线索api
 * https://open.oceanengine.com/labels/7/docs/1696710631271436
 * <p>
 * API 需要的properties
 * advertiser_id： 广告主id --  使用accountId字段配置
 * app_id : appKey
 * secret : appSecret
 */
@Slf4j
public class FeiYuChannelClient extends AdChannelClient {


    // 授权回调通知地址
    private static final String AUTH_REDIRECT_URI = "https://scrm-admin.jzsaas.com/open-api/ad/auth/token-redirect/douyin";

    // 获取token
    private static final String GET_TOKEN_API = "https://ad.oceanengine.com/open_api/oauth2/access_token/";

    // 刷新token
    private static final String REFRESH_TOKEN_API = "https://ad.oceanengine.com/open_api/oauth2/refresh_token/";

    private static final String CRM_API_KEY = "1787436524605609";
    private static final String CRM_API_SECRET = "a1f61376ea0ab46ab56bbbf775bad71c59a08ecd";

    private static final Integer CRM_SOURCE = 102;

    public FeiYuChannelClient(AdChannelProperties properties) {
        super(properties);
    }

    /**
     * 逻辑上定义为每分钟执行一次， 查询开始和结束时间为， LastQueryTime - 1min, LastQueryTime; => LastQueryTime = now() - 10min;
     *
     * @param reqDTO
     * @return
     * @author PetePower
     * @since 2024-06-17
     */
    @Override
    public List<ClueSyncRespDTO> getClue(ClueSyncReqDTO reqDTO) {
        int pageIndex = reqDTO.getPageNo();
        int pageSize = 100;

        // 如果首次查询时， startTime是空的， 那么直接指定到今年第一天
        LocalDateTime startTime = DateUtil.beginOfYear(new Date()).toLocalDateTime();
        if (Objects.nonNull(reqDTO.getStartTime())) {
            startTime = reqDTO.getStartTime();
        }
        List<ClueSyncRespDTO> dataList = getDataList(
                reqDTO.getAdvertiserStrId(),
                pageIndex,
                pageSize,
                LocalDateTimeUtil.format(startTime, DatePattern.NORM_DATETIME_FORMATTER),
                LocalDateTimeUtil.format(reqDTO.getEndTime(), DatePattern.NORM_DATETIME_FORMATTER),
                reqDTO.getAccessToken()
        );

        return dataList;
    }

    @Override
    public String genAuthUrl() {
        // https://developers.e.kuaishou.com/tools/authorize
        String url = "https://open.oceanengine.com/audit/oauth.html";
        Map<String, Object> params = new HashMap<>();
        params.put("app_id", getApiKey());
        params.put("scope", new int[]{1,2,3,4,5,8,9,10000000});
//        params.put("scope", URLUtil.encode(ListUtil.toList().toString()));
        params.put("redirect_uri", URLUtil.encode(AUTH_REDIRECT_URI));
        params.put("material_auth", 1);
//        params.put("oauth_type", "advertiser");
        params.put("state", "TenantId:" + TenantContextHolder.getTenantId() + ",AccountId:" + properties.getId());
        return StrUtil.concat(true, url, "?", HttpUtil.toParams(params, CharsetUtil.CHARSET_UTF_8, true));
    }

    @Override
    public TokenGenRespDTO genToken(Map<String, String> params) {
        Map<String, Object> data = new HashMap<>();
        data.put("app_id", getApiKey());
        data.put("secret", getApiSecret());
        data.put("grant_type", "auth_code");
        data.put("auth_code", params.get("auth_code"));
        log.info("获取accessToken: 入参： ------------------- ");
        log.info(data.toString());
        HttpResponse httpResponse = HttpUtil.createPost(GET_TOKEN_API)
                .header(Header.CONTENT_TYPE, ContentType.JSON.getValue())
                .body(JSONUtil.toJsonStr(data)).execute();
        String result = httpResponse.body();
        log.info("获取accessToken: 返回： ------------------- ");
        log.info(result);
        JSONObject jsonObject = JSONUtil.parseObj(result);
        if (ObjectUtil.equal(0, jsonObject.getInt("code"))) {
            String accessToken = jsonObject.getJSONObject("data").getStr("access_token");
            String refreshToken = jsonObject.getJSONObject("data").getStr("refresh_token");
            Integer access_token_expires_in = jsonObject.getJSONObject("data").getInt("expires_in");
            return TokenGenRespDTO.builder()
                    .accessToken(accessToken)
                    .refreshToken(refreshToken)
                    .expireIn(access_token_expires_in)
                    .build();

        }
        return null;
    }

    @Override
    public List<AdvertiserRespDTO> getAdvertiserList(String accessToken) {
        String url = "https://ad.oceanengine.com/open_api/oauth2/advertiser/get/";
        Map<String, Object> data = new HashMap<>();
        data.put("app_id", getApiKey());
        data.put("secret", getApiSecret());
        data.put("access_token", accessToken);
        String result = HttpUtil.get(url, data);
        JSONObject jsonObject = JSONUtil.parseObj(result);
        if (ObjectUtil.equal(0, jsonObject.getInt("code"))) {
            JSONObject resultData = jsonObject.getJSONObject("data");
            JSONArray jsonArray = resultData.getJSONArray("list");
            if (Objects.nonNull(jsonArray) && !jsonArray.isEmpty()) {
                return BeanUtils.toBean(jsonArray, AdvertiserRespDTO.class);
            }
        }
        return Collections.emptyList();
    }

    @Override
    public List<AdvertiserRespDTO> getAdvertiserAccountList(String accessToken, String advertiserId) {
        String url = "https://ad.oceanengine.com/open_api/2/majordomo/advertiser/select/";
        Map<String, Object> data = new HashMap<>();
        data.put("app_id", getApiKey());
        data.put("secret", getApiSecret());
        data.put("advertiser_id", advertiserId);

        log.info("getAdvertiserAccountList>>>>> {}", data);
        HttpResponse httpResponse = HttpUtil.createGet(url )
                .body(JSONUtil.toJsonStr(data))
                .header(Header.CONTENT_TYPE, ContentType.JSON.getValue())
                .header("Access-Token", accessToken)
                .execute();
        String result = httpResponse.body();

        JSONObject jsonObject = JSONUtil.parseObj(result);
        log.info("getAdvertiserAccountList>>>>> {}", jsonObject);
        if (ObjectUtil.equal(0, jsonObject.getInt("code"))) {
            JSONObject resultData = jsonObject.getJSONObject("data");
            JSONArray jsonArray = resultData.getJSONArray("list");
            if (Objects.nonNull(jsonArray) && !jsonArray.isEmpty()) {
                return BeanUtils.toBean(jsonArray, AdvertiserRespDTO.class);
            }
        }
        return Collections.emptyList();
    }

    @Override
    public TokenGenRespDTO refreshToken(String accessToken, String refreshToken) {
        Map<String, Object> data = new HashMap<>();
        data.put("app_id", getApiKey());
        data.put("secret", getApiSecret());
        data.put("refresh_token", refreshToken);
        data.put("grant_type", "refresh_token");
        HttpResponse httpResponse = HttpUtil.createPost(REFRESH_TOKEN_API)
                .header(Header.CONTENT_TYPE, ContentType.JSON.getValue())
                .body(JSONUtil.toJsonStr(data)).execute();
        String result = httpResponse.body();
        JSONObject jsonObject = JSONUtil.parseObj(result);
        if (ObjectUtil.equal(0, jsonObject.getInt("code"))) {
            Integer access_token_expires_in = jsonObject.getJSONObject("data").getInt("expires_in");
            return TokenGenRespDTO.builder()
                    .accessToken(jsonObject.getJSONObject("data").getStr("access_token"))
                    .refreshToken(jsonObject.getJSONObject("data").getStr("refresh_token"))
                    .expireIn(access_token_expires_in)
                    .build();

        }
        return null;
    }

    private List<ClueSyncRespDTO> getDataList(String advertiserStrId, Integer pageNo, Integer pageSize, String startTime, String endTime, String accessToken) {
        String url = "https://ad.oceanengine.com/open_api/2/tools/clue/get/";
        Map<String, Object> data = new HashMap<>();
        data.put("advertiser_ids", ListUtil.toList(advertiserStrId));
        data.put("start_time", startTime);
        data.put("end_time", endTime);
        data.put("page", pageNo);
        data.put("page_size", pageSize);
        HttpResponse httpResponse = HttpUtil.createGet(url)
                .body(JSONUtil.toJsonStr(data))
                .header(Header.CONTENT_TYPE, ContentType.JSON.getValue())
                .header("Access-Token", accessToken)
                .execute();
        String result = httpResponse.body();
        JSONObject jsonObject = JSONUtil.parseObj(result);
        // 先处理返回集合的转换
        List<ClueSyncRespDTO> resultDataList = new ArrayList<>();
        if (ObjectUtil.notEqual(0, jsonObject.getInt("code"))) {
            return Collections.emptyList();
        }

        JSONObject resultData = jsonObject.getJSONObject("data");
        JSONArray jsonArray = resultData.getJSONArray("list");

        if (Objects.nonNull(jsonArray) && !jsonArray.isEmpty()) {
            jsonArray.forEach(jsonData -> {
                resultDataList.add(beanToResp(JSONUtil.parseObj(jsonData)));
            });
        }
        return resultDataList;
    }

    private ClueSyncRespDTO beanToResp(JSONObject jsonObject) {
        // 相同字段或json驼峰直接toBean
        ClueSyncRespDTO resp = BeanUtils.toBean(jsonObject, ClueSyncRespDTO.class);
        resp.setCrmSource(CRM_SOURCE);
        // 广告主id
        resp.setAdvertiserId(jsonObject.getStr("advertiser_id"));
        // 线索姓名转化
        resp.setClueName(jsonObject.getStr("name"));
        // 线索手机号
        resp.setTelephone(jsonObject.getStr("telephone"));

        // 计划id --- 落地页id
        resp.setPromotionId(jsonObject.getStr("ad_id"));
//        resp.setPromotionName(jsonObject.getStr("ad_name"));

        // 线索来源转换
        resp.setActionType(actionTypeMapping(jsonObject.getInt("clue_source")));
        // 流量类型
//        resp.setFlowType(flowTypeMapping(jsonObject.getInt("channel_flag")));
        // 客资组件类型转换
        resp.setClueType(clueTypeMapping(jsonObject.getInt("clue_type")));
        // 线索状态转换
        resp.setClueStatus(jsonObject.getStr("clue_state_name"));
        // 跟进状态转换
        resp.setFollowStatus(jsonObject.getStr("follow_state_name"));

        // 分配类型
        resp.setAllocationStatus(allocationStatusMapping(jsonObject.getInt("allocation_status")));
        // 原始线索id
        resp.setAdClueId(jsonObject.getStr("clue_id"));
        resp.setClueCreateTime(jsonObject.getStr("create_time_detail"));

        return resp;

    }

    private String allocationStatusMapping(Integer allocationStatus) {
        if (Objects.isNull(allocationStatus)) {
            return "未知";
        }
        switch (allocationStatus) {
            case 0:
                return "待分配";
            case 1:
                return "已分配";
        }
        return "未知";
    }

//
//    /**
//     * 跟进状态转换
//     * @since 2024-06-17
//     * @author PetePower
//            1：广告流量；2：其他
//     * @return
//     */
//    private String flowTypeMapping(Integer channelFlag) {
//        if (Objects.isNull(channelFlag)) {
//            return "其他";
//        }
//        switch (channelFlag) {
//            case 2:
//                return "其他";
//            case 1:
//                return "广告流量";
//        }
//        return "其他";
//    }

    /**
     * 线索来源枚举转换
     *
     * @param actionType
     * @return
     * @author PetePower
     * 1003:建站；1005:线索通；1007:投放平台；1008:联盟广告；1010:虚拟商品推广；1011:快聊；1021:快说车小程序；1023:服务号；
     * @since 2024-06-17
     */
    private String actionTypeMapping(Integer actionType) {
        if (Objects.isNull(actionType)) {
            return "未知";
        }
        switch (actionType) {
            case 0:
                return "外部流量";
            case 1:
                return "正常投放";
            case 2:
                return "外部导入";
            case 3:
                return "异常提交";
            case 4:
                return "广告预览";
            case 5:
                return "抖音私信";
            case 6:
                return "鲁班线索";
        }
        return "未知";
    }

    /**
     * 线索状态枚举转换
     *
     * @param clueStatus
     * @return
     * @author PetePower
     * 线索状态值
     * 0：未标记；1：无意向；2：潜在客户；3：高价值客户；4：已成单
     * @since 2024-06-17
     */
    private String clueStatusMapping(Integer clueStatus) {
        if (Objects.isNull(clueStatus)) {
            return AdClueStatusEnum.OTHER.getName();
        }
        switch (clueStatus) {
            case 0:
                return "未标记";
            case 1:
                return AdClueStatusEnum.NEW.getName();
            case 2:
                return AdClueStatusEnum.INTENTION.getName();
            case 4:
                return AdClueStatusEnum.INVALID.getName();
            case 3:
                return AdClueStatusEnum.BUSINESS.getName();
            case 5:
                return AdClueStatusEnum.CONTACT.getName();
            case 7:
                return AdClueStatusEnum.WAIT_NEXT_CONTACT.getName();
        }
        return AdClueStatusEnum.OTHER.getName();
    }

    /**
     * 留资组件枚举转换
     *
     * @param clueType
     * @return
     * @author PetePower
     * 1：表单；2：智能电话 3：咨询页
     * @since 2024-06-17
     */
    private String clueTypeMapping(Integer clueType) {
        if (Objects.isNull(clueType)) {
            return AdClueTypeEnum.OTHER.getName();
        }
        switch (clueType) {
            case 0:
                return AdClueTypeEnum.FORM.getName();
            case 1:
                return AdClueTypeEnum.ADVISORY.getName();
            case 2:
                return AdClueTypeEnum.TEL.getName();
            case 3:
                return "网页回呼";
            case 4:
                return "卡券";
            case 5:
                return "抽奖";
        }
        return AdClueTypeEnum.OTHER.getName();
    }

    public String getApiKey() {
        if (properties.getAuthType() == 1) {
            return properties.getApiKey();
        } else {
            return CRM_API_KEY;
        }
    }

    public String getApiSecret() {
        if (properties.getAuthType() == 1) {
            return properties.getApiSecret();
        } else {
            return CRM_API_SECRET;
        }
    }


}
